package fr.inserm.u674.chcdbweb.view.ajax.dhmlx;

import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.text.Normalizer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.jdom.Element;
import org.jdom.output.XMLOutputter;

import fr.inserm.u674.chcdbweb.model.DTO.EAVVariable;
import fr.inserm.u674.chcdbweb.model.DTO.Tissue;
import fr.inserm.u674.chcdbweb.model.DTO.TissueExtraction;
import fr.inserm.u674.chcdbweb.model.DTO.TissueExtractionRNA;
import fr.inserm.u674.chcdbweb.model.DTO.TissueType;

public class DHTMLXWriter {

	private static DHTMLXWriter instance;

	private DHTMLXWriter() {
	}

	public static DHTMLXWriter getInstance() {
		if (instance == null)
			instance = new DHTMLXWriter();
		return instance;
	}

	public String writeXMLTissueExtractionGrid(List<TissueExtraction> extractionList)
		throws IOException {
		StringBuffer xml = new StringBuffer();
		xml.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
		xml.append("<rows>\n");
		for (TissueExtraction extraction : extractionList) {
			Tissue tissueManipulated = extraction.getTissueManipulated();
			Tissue masterTissue = tissueManipulated.getMasterTissue();
			xml.append("<row id=\"" + extraction.getManipulationID() + "\" >\n");

			xml.append("<cell style=\"font-family: courier;\" type=\"ro\">");
			xml.append(encloseWithGridTissuelink(tissueManipulated, tissueManipulated.toString()));
			xml.append("</cell>");

			xml.append("<cell type=\"ro\">");
			xml.append(tissueManipulated.getChcID());
			xml.append("</cell>");

			xml.append("<cell type=\"ro\">");
			xml.append(tissueManipulated.getTissueTypeID());
			xml.append("</cell>");

			xml.append("<cell style=\"font-family: courier;\" type=\"ro\">");
			if (masterTissue != null)
				xml.append(encloseWithGridTissuelink(masterTissue, masterTissue.toString()
					.toString()));
			else
				xml.append("-------");
			xml.append("</cell>");

			xml.append("<cell>");
			xml.append(extraction.getExperimenter().getInitials() != null ? extraction
				.getExperimenter().getInitials()
				: "");
			xml.append("</cell>");

			xml.append("<cell>");
			xml.append(extraction.getConcentration());
			xml.append("</cell>");

			xml.append("<cell>");
			xml.append(extraction.getFinalVolume());
			xml.append("</cell>");

			xml.append("<cell>");
			xml.append(extraction.getQuantityExtracted());
			xml.append("</cell>");

			xml.append("<cell>");
			Boolean empty = extraction.getEmptyTube();
			xml.append(empty != null && empty == true ? "true"
				: "");
			xml.append("</cell>");

			xml.append("<cell>");
			xml.append(extraction.getQualityExtractionGel() != null ? extraction
				.getQualityExtractionGel()
				: "");
			xml.append("</cell>");

			xml.append("<cell>");
			xml.append(extraction.getQuantityTissueLeftAfterManipulation() != null ? extraction
				.getQuantityTissueLeftAfterManipulation()
				: "");
			xml.append("</cell>");

			xml.append("<cell>");
			xml.append(extraction.getManipulationDate() != null ? extraction.getManipulationDate()
				: "");
			xml.append("</cell>");

			xml.append("<cell type=\"ro\">");
			xml.append(extraction.getExtractionType());
			xml.append("</cell>");

			xml.append("<cell>");
			xml.append(extraction.getExtractionComment() != null ? extraction
				.getExtractionComment().replaceAll("\\>", "&gt;").replaceAll("\\<", "&lt;")
				: "");
			xml.append("</cell>");

			if (extraction instanceof TissueExtractionRNA) {

				TissueExtractionRNA extractionRNA = (TissueExtractionRNA) extraction;

				xml.append("<cell>");
				xml.append(extractionRNA.getDo260do280() != null ? extractionRNA.getDo260do280()
					: "");
				xml.append("</cell>");

				xml.append("<cell>");
				xml.append(extractionRNA.getAgilentDate() != null ? extractionRNA.getAgilentDate()
					: "");
				xml.append("</cell>");

				xml.append("<cell>");
				xml.append(extractionRNA.getAgilent28S18S() != null ? extractionRNA
					.getAgilent28S18S()
					: "");
				xml.append("</cell>");

				xml.append("<cell>");
				xml.append(extractionRNA.getExtractionMethod() != null ? extractionRNA
					.getExtractionMethod()
					: "");
				xml.append("</cell>");
			}

			else {
				xml.append("<cell type=\"ro\">");
				xml.append("--");
				xml.append("</cell>");

				xml.append("<cell type=\"ro\">");
				xml.append("--");
				xml.append("</cell>");

				xml.append("<cell type=\"ro\">");
				xml.append("--");
				xml.append("</cell>");

				xml.append("<cell type=\"ro\">");
				xml.append("--");
				xml.append("</cell>");

			}

			xml.append("</row>\n");

		}

		xml.append("</rows>\n");
		String xmlString = xml.toString();
		return xmlString;
	}

	public void writeXMLTissueExtractionGridToOutputStream(List<TissueExtraction> extractionList,
		OutputStream outputStream) throws IOException {
		StringBuffer xml = new StringBuffer();
		xml.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
		xml.append("<rows>\n");
		for (TissueExtraction extraction : extractionList) {
			Tissue tissueManipulated = extraction.getTissueManipulated();
			Tissue masterTissue = tissueManipulated.getMasterTissue();
			xml.append("<row id=\"" + extraction.getManipulationID() + "\" >\n");

			xml.append("<cell style=\"font-family: courier;\" type=\"ro\">");
			xml.append(encloseWithGridTissuelink(tissueManipulated, tissueManipulated.toString()));
			xml.append("</cell>");

			xml.append("<cell type=\"ro\">");
			xml.append(tissueManipulated.getChcID());
			xml.append("</cell>");

			xml.append("<cell type=\"ro\">");
			xml.append(tissueManipulated.getTissueTypeID());
			xml.append("</cell>");

			xml.append("<cell style=\"font-family: courier;\" type=\"ro\">");
			if (masterTissue != null)
				xml.append(encloseWithGridTissuelink(masterTissue, masterTissue.toString()
					.toString()));
			else
				xml.append("-------");
			xml.append("</cell>");

			xml.append("<cell>");
			xml.append(extraction.getExperimenter().getInitials() != null ? removeAccents(extraction
				.getExperimenter().getInitials().replaceAll("\\>", "&gt;")
				.replaceAll("\\<", "&lt;"))
				: "");
			xml.append("</cell>");

			xml.append("<cell>");
			xml.append(extraction.getConcentration());
			xml.append("</cell>");

			xml.append("<cell>");
			xml.append(extraction.getFinalVolume());
			xml.append("</cell>");

			xml.append("<cell>");
			xml.append(extraction.getQuantityExtracted());
			xml.append("</cell>");

			xml.append("<cell>");
			Boolean empty = extraction.getEmptyTube();
			xml.append(empty != null && empty == true ? "true"
				: "");
			xml.append("</cell>");

			xml.append("<cell>");
			xml.append(extraction.getQualityExtractionGel() != null ? removeAccents(extraction
				.getQualityExtractionGel().replaceAll("\\>", "&gt;").replaceAll("\\<", "&lt;"))
				: "");
			xml.append("</cell>");

			xml.append("<cell>");
			xml.append(extraction.getQuantityTissueLeftAfterManipulation() != null ? removeAccents(extraction
				.getQuantityTissueLeftAfterManipulation().replaceAll("\\>", "&gt;").replaceAll(
					"\\<", "&lt;"))
				: "");
			xml.append("</cell>");

			xml.append("<cell>");
			xml.append(extraction.getManipulationDate() != null ? extraction.getManipulationDate()
				: "");
			xml.append("</cell>");

			xml.append("<cell type=\"ro\">");
			xml.append(removeAccents(extraction.getExtractionType().replaceAll("\\>", "&gt;")
				.replaceAll("\\<", "&lt;")));
			xml.append("</cell>");

			xml.append("<cell>");
			xml.append(extraction.getExtractionComment() != null ? removeAccents(extraction
				.getExtractionComment().replaceAll("\\>", "&gt;").replaceAll("\\<", "&lt;"))
				: "");
			xml.append("</cell>");

			if (extraction instanceof TissueExtractionRNA) {

				TissueExtractionRNA extractionRNA = (TissueExtractionRNA) extraction;

				xml.append("<cell>");
				xml.append(extractionRNA.getDo260do280() != null ? extractionRNA.getDo260do280()
					: "");
				xml.append("</cell>");

				xml.append("<cell>");
				xml.append(extractionRNA.getAgilentDate() != null ? extractionRNA.getAgilentDate()
					: "");
				xml.append("</cell>");

				xml.append("<cell>");
				xml.append(extractionRNA.getAgilent28S18S() != null ? extractionRNA
					.getAgilent28S18S()
					: "");
				xml.append("</cell>");

				xml.append("<cell>");
				xml.append(extractionRNA.getExtractionMethod() != null ? removeAccents(extractionRNA
					.getExtractionMethod().replaceAll("\\>", "&gt;").replaceAll("\\<", "&lt;"))
					: "");
				xml.append("</cell>");
			}

			else {
				xml.append("<cell type=\"ro\">");
				xml.append("--");
				xml.append("</cell>");

				xml.append("<cell type=\"ro\">");
				xml.append("--");
				xml.append("</cell>");

				xml.append("<cell type=\"ro\">");
				xml.append("--");
				xml.append("</cell>");

				xml.append("<cell type=\"ro\">");
				xml.append("--");
				xml.append("</cell>");

			}

			xml.append("</row>\n");
			outputStream.write(xml.toString().getBytes(Charset.forName("UTF-8")));
			xml.setLength(0);
		}

		xml.append("</rows>\n");
		outputStream.write(xml.toString().getBytes(Charset.forName("UTF-8")));
	}

	public String writeXMLTissueGrid(List<Tissue> tissueList, String[] eavVariableNamesToDisplay,
		Boolean showTissueQuantities) throws IOException {
		ArrayList<String> list = new ArrayList<String>();
		for (int i = 0; i < eavVariableNamesToDisplay.length; i++)
			list.add(eavVariableNamesToDisplay[i]);
		return writeXMLTissueGrid(tissueList, list, showTissueQuantities);
	}

	public void writeXMLTissueGridToOutputStream(List<Tissue> tissueList, String[] eavVariableNamesToDisplay,
		Boolean showTissueQuantities, OutputStream outStream) throws IOException {
		ArrayList<String> list = new ArrayList<String>();
		for (int i = 0; i < eavVariableNamesToDisplay.length; i++)
			list.add(eavVariableNamesToDisplay[i]);
		writeXMLTissueGridToOutputStream(tissueList, list, showTissueQuantities, outStream);
	}

	public String writeXMLTissueGrid(List<Tissue> tissueList,
		ArrayList<String> eavVariablesNamesToDisplay, Boolean showTissueQuantities)
		throws IOException {
		StringBuffer xml = new StringBuffer();
		xml.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
		if (tissueList != null) {
			xml.append("<rows>\n");
			for (Tissue tissue : tissueList) {
				Tissue masterTissue = tissue.getMasterTissue();
				xml.append("<row id=\"" + tissue.toString() + "\" >\n");

				xml.append("<cell style=\"font-family: courier;\" type=\"ro\">");
				xml.append(encloseWithGridTissuelink(tissue, tissue.toString()));
				xml.append("</cell>");

				xml.append("<cell type=\"ro\">");
				xml.append(tissue.getChcID());
				xml.append("</cell>");

				xml.append("<cell type=\"ro\">");
				xml.append(tissue.getTissueTypeID());
				xml.append("</cell>");

				xml.append("<cell style=\"font-family: courier;\" type=\"ro\">");
				if (masterTissue != null)
					xml.append(encloseWithGridTissuelink(masterTissue, masterTissue.toString()));
				else
					xml.append("-------");
				xml.append("</cell>");

				for (String eavVariableNametoDisplay : eavVariablesNamesToDisplay) {
					xml.append("<cell>");
					String modality = "";
					if (tissue.getEavData().get(eavVariableNametoDisplay).getModality() != null) {
						modality = tissue.getEavData().get(eavVariableNametoDisplay).getModality();
						modality = modality.replaceAll("\\<", "&lt;");
						modality = modality.replaceAll("\\>", "&gt;");
					}
					xml.append(modality);
					xml.append("</cell>");

				}
				if (showTissueQuantities) {
					xml.append("<cell>");
					xml.append(tissue.getQuantityLeft() != null ? tissue.getQuantityLeft()
						: "");
					xml.append("</cell>");
				}

				xml.append("</row>\n");

			}
		}
		xml.append("</rows>\n");
		String xmlString = xml.toString();
		return xmlString;
	}

	public void writeXMLTissueGridToOutputStream(List<Tissue> tissueList,
		ArrayList<String> eavVariablesNamesToDisplay, Boolean showTissueQuantities,
		OutputStream outStream) throws IOException {
		StringBuffer xml = new StringBuffer();
		xml.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
		if (tissueList != null) {
			xml.append("<rows>\n");
			for (Tissue tissue : tissueList) {
				Tissue masterTissue = tissue.getMasterTissue();
				xml.append("<row id=\"" + tissue.toString() + "\" >\n");

				xml.append("<cell style=\"font-family: courier;\" type=\"ro\">");
				xml.append(encloseWithGridTissuelink(tissue, tissue.toString()));
				xml.append("</cell>");

				xml.append("<cell type=\"ro\">");
				xml.append(tissue.getChcID());
				xml.append("</cell>");

				xml.append("<cell type=\"ro\">");
				xml.append(tissue.getTissueTypeID());
				xml.append("</cell>");

				xml.append("<cell style=\"font-family: courier;\" type=\"ro\">");
				if (masterTissue != null)
					xml.append(encloseWithGridTissuelink(masterTissue, masterTissue.toString()));
				else
					xml.append("-------");
				xml.append("</cell>");

				for (String eavVariableNametoDisplay : eavVariablesNamesToDisplay) {
					xml.append("<cell>");
					String modality = "";
					if (tissue.getEavData().get(eavVariableNametoDisplay).getModality() != null) {
						modality = tissue.getEavData().get(eavVariableNametoDisplay).getModality();
						modality = modality.replaceAll("\\<", "&lt;");
						modality = modality.replaceAll("\\>", "&gt;");
					}
					xml.append(modality);
					xml.append("</cell>");

				}
				if (showTissueQuantities) {
					xml.append("<cell>");
					xml.append(tissue.getQuantityLeft() != null ? tissue.getQuantityLeft()
						: "");
					xml.append("</cell>");
				}

				xml.append("</row>\n");
				outStream.write(xml.toString().getBytes(Charset.forName("UTF-8")));
				xml.setLength(0);

			}
		}
		xml.append("</rows>\n");
		outStream.write(xml.toString().getBytes(Charset.forName("UTF-8")));

	}

	public String writeEAVVarListTable(List<EAVVariable> varList, boolean humanReadable) {
		String finalString;
		Element rows = new Element("rows");
		Element row;
		for (EAVVariable eVar : varList) {
			row = new Element("row");
			row.setAttribute("id", eVar.getVariableID().toString());
			Element cell;
			cell = new Element("cell");
			cell.setAttribute("style", "font-size: 12px; font-family: courier");
			cell.setText(eVar.getVariableName());
			row.addContent(cell);
			cell = new Element("cell");
			cell.setText(eVar.getHumanReadableName());
			row.addContent(cell);

			cell = new Element("cell");
			cell.setText(eVar.getDataType());

			row.addContent(cell);

			cell = new Element("cell");
			cell.setText(eVar.getCreationDate().toString());
			row.addContent(cell);
			cell = new Element("cell");
			cell.setText(eVar.getDeprecated() ? "YES"
				: "NO");
			row.addContent(cell);
			cell = new Element("cell");
			cell.setText(eVar.getDescription());
			row.addContent(cell);

			rows.addContent(row);

		}

		XMLOutputter outputter = new XMLOutputter();
		finalString = outputter.outputString(rows);

		return finalString;
	}

	public String writeDHTMLXGridEAVVariableModalities(HashMap<String, Integer> modalities) {
		Element rows = new Element("rows");

		Element row;
		int count = 1;
		for (String modality : modalities.keySet()) {
			row = new Element("row");
			row.setAttribute("id", Integer.toString(count));

			Element cell = new Element("cell");
			cell.setText(modality);
			row.addContent(cell);

			cell = new Element("cell");
			cell.setText(modalities.get(modality).toString());
			row.addContent(cell);

			rows.addContent(row);

			count++;
		}

		String finalString = new XMLOutputter().outputString(rows);
		return finalString;
	}

	public String writeDHTMLXTissueTypeGrid(List<TissueType> list) {
		Element rows = new Element("rows");
		String xmlString = new String();

		Element row = null;
		for (TissueType tt : list) {
			row = new Element("row");
			row.setAttribute("id", tt.getTissueTypeID());

			Element cell = new Element("cell");
			cell.setText(tt.getTissueTypeID());
			row.addContent(cell);

			cell = new Element("cell");
			cell.setText(tt.getTissueTypeDescription() != null ? tt.getTissueTypeDescription()
				: "");
			row.addContent(cell);

			cell = new Element("cell");
			Integer n = tt.getOccurrencesInDB();
			cell.setText(n != null ? n.toString()
				: "");
			row.addContent(cell);

			rows.addContent(row);

		}

		xmlString = new XMLOutputter().outputString(rows);

		return xmlString;
	}

	public String writeHTMLErrorMessage(String messageString, Boolean userException) {

		Element message = new Element("div");
		message.setAttribute("id", "message");
		message.setAttribute("style", "font-size:12px;");

		if (!userException) {
			Element messageHead = new Element("div");
			messageHead.setAttribute("id", "messageHead");
			messageHead
				.setText("An error ocurred, please send the following error message to the administrator :");
			message.addContent(messageHead);
		}
		Element messageError = new Element("div");
		messageError.setAttribute("id", "messageError");
		messageError.setAttribute("style", "color: red;font-family: courier;");
		messageError.setText(messageString.replaceAll("\\n", "<br>"));

		message.addContent(messageError);

		return new XMLOutputter().outputString(message);
	}

	public String writeDHTMLXTissueToolbarXML(List<EAVVariable> list) {
		Element toolbar = new Element("toolbar");

		Element varListButton = new Element("item");
		varListButton.setAttribute("id", "varList");
		varListButton.setAttribute("type", "buttonSelect");
		varListButton.setAttribute("maxOpen", "5");
		varListButton.setAttribute("text", "variables");

		for (EAVVariable var : list) {
			Element varListItem = new Element("item");
			varListItem.setAttribute("id", var.getVariableName());
			varListItem.setAttribute("text", var.getHumanReadableName());
			varListButton.addContent(varListItem);
		}

		toolbar.addContent(varListButton);
		String response = new XMLOutputter().outputString(toolbar);
		return response;
	}

	public String writeDHTMLXGrid() {
		return null;
	}

	/**
	 * @param tissue
	 *            the Tissue for which a DHTMLXGrid cell compliant hyperlinklink is to be
	 *            genereated. This link is supposed to be inserted into a DHTMLXGrid cell (special
	 *            HTML characters : <,>,& are escaped in the HTML sense.)
	 * @param initialString
	 *            The String which is to be enclosed in the DHTMLXGrid cell compliant hyperlink
	 * @return
	 */
	private String encloseWithGridTissuelink(Tissue tissue, String initialString) {
		StringBuffer buffer = new StringBuffer();

		buffer
			.append("&lt;a target=\"_blank\" href=\"mainServlet?appAction=displayTissue&amp;chcID="
				+ tissue.getChcID() + "&amp;tissueTypeID=" + tissue.getTissueTypeID() + "\"&gt;");
		buffer.append(initialString);
		buffer.append("&lt;/a&gt;");

		return buffer.toString();
	}

	private String removeAccents(String s) {
		return Normalizer.normalize(s, Normalizer.Form.NFD);
	}
}
